﻿#include "MysqlDao.h"
#include "ConfigMgr.h"

MysqlDao::MysqlDao()
{
	auto & cfg = ConfigMgr::Inst();
	const auto& host = cfg["Mysql"]["Host"];
	const auto& port = cfg["Mysql"]["Port"];
	const auto& pwd = cfg["Mysql"]["Password"];
	const auto& schema = cfg["Mysql"]["Schema"];
	const auto& user = cfg["Mysql"]["User"];
	pool_.reset(new MySqlPool(host+":"+port, user, pwd,schema, 5));
}

MysqlDao::~MysqlDao(){
	pool_->Close();
}

int MysqlDao::RegUserTransaction(const std::string& name, const std::string& email, const std::string& pwd)
{
	// 生成密码哈希future对象为了和sql事务并行执行
	auto hashFuture = _bcryptWorker.generateHashAsync(pwd);

	auto con = pool_->getConnection();
	if (!con) return -1;

	Defer defer([this, &con] { pool_->returnConnection(std::move(con)); });

	try {
		//开始事务
		con->_con->setAutoCommit(false);

		//执行第一个数据库操作，根据email查找用户是否存在
		// 准备查询语句
		std::unique_ptr<sql::PreparedStatement> pstmt_email(con->_con->prepareStatement("SELECT 1 FROM user WHERE email = ?"));

		// 绑定参数
		pstmt_email->setString(1, email);

		// 执行查询
		std::unique_ptr<sql::ResultSet> res_email(pstmt_email->executeQuery());

		auto email_exist = res_email->next();
		if (email_exist) {
			con->_con->rollback();
			std::cout << "email " << email << " exist" <<std::endl;
			return 0;
		}

		// 确保哈希完成 
		auto hash_pwd = hashFuture.get();
		std::cout<<hash_pwd<<std::endl;

		//  插入用户数据
		std::unique_ptr<sql::PreparedStatement> pstmt_insert(
			con->_con->prepareStatement(
				"INSERT INTO user (email, password_hash, user_name) "
				"VALUES (?, ?, ?)"
			)
		);
		pstmt_insert->setString(1, email);
		pstmt_insert->setString(2, hash_pwd);
		pstmt_insert->setString(3, name);
		pstmt_insert->executeUpdate();

		// ▶ 获取自增UID（通过独立查询）
		std::unique_ptr<sql::Statement> stmt(con->_con->createStatement());
		std::unique_ptr<sql::ResultSet> res(stmt->executeQuery("SELECT LAST_INSERT_ID()"));
		int newId = 0;
		if (res->next()) {
			newId = res->getInt(1);
		}
		else {
			con->_con->rollback();
			return -1;
		}

		con->_con->commit();
		return newId; // 成功返回新UID 
	}
	catch (sql::SQLException& e) {
		std::cerr << "数据库异常: " << e.what()
			<< "\n错误代码: " << e.getErrorCode()
			<< "\nSQL状态: " << e.getSQLState() << std::endl;
		return -1;
	}
}

//需要邮箱存在
int MysqlDao::CheckEmail_reset(const std::string& email)
{
	auto con = pool_->getConnection();
	if (con == nullptr) {
		return false;
	}

	Defer defer([this, &con] {
		pool_->returnConnection(std::move(con));
		});

	try {
		//开始事务
		con->_con->setAutoCommit(false);
		//执行第一个数据库操作，根据email查找用户
		// 准备查询语句

		std::unique_ptr<sql::PreparedStatement> pstmt_email(con->_con->prepareStatement("SELECT 1 FROM user WHERE email = ?"));

		// 绑定参数
		pstmt_email->setString(1, email);

		// 执行查询
		std::unique_ptr<sql::ResultSet> res_email(pstmt_email->executeQuery());

		auto email_exist = res_email->next();
		// 如果查询结果不为空，表示邮箱已存在
		if (email_exist) {
			con->_con->rollback();
			std::cout << "email " << email << " is valid";
			return ErrorCodes::Success;
		}
		return ErrorCodes::EmailNotExist;
	}
	catch (sql::SQLException& e) {
		// 如果发生错误，回滚事务
		if (con) {
			con->_con->rollback();
		}
		std::cerr << "SQLException: " << e.what();
		std::cerr << " (MySQL error code: " << e.getErrorCode();
		std::cerr << ", SQLState: " << e.getSQLState() << " )" << std::endl;
		return -1;
	}
	return 0;
}

//需要邮箱不存在
int MysqlDao::CheckEmail_reg(const std::string& email)
{
	auto con = pool_->getConnection();
	if (con == nullptr) {
		return false;
	}

	Defer defer([this, &con] {
		pool_->returnConnection(std::move(con));
		});

	try {
		//开始事务
		con->_con->setAutoCommit(false);
		//执行第一个数据库操作，根据email查找用户
		// 准备查询语句

		std::unique_ptr<sql::PreparedStatement> pstmt_email(con->_con->prepareStatement("SELECT 1 FROM user WHERE email = ?"));

		// 绑定参数
		pstmt_email->setString(1, email);

		// 执行查询
		std::unique_ptr<sql::ResultSet> res_email(pstmt_email->executeQuery());

		auto email_exist = res_email->next();
		// 如果查询结果不为空，表示邮箱已存在
		if (email_exist) {
			con->_con->rollback();
			std::cout << "email " << email << " is valid";
			return ErrorCodes::EmailExist;
		}
		return ErrorCodes::Success;
	}
	catch (sql::SQLException& e) {
		// 如果发生错误，回滚事务
		if (con) {
			con->_con->rollback();
		}
		std::cerr << "SQLException: " << e.what();
		std::cerr << " (MySQL error code: " << e.getErrorCode();
		std::cerr << ", SQLState: " << e.getSQLState() << " )" << std::endl;
		return -1;
	}
	return 0;
}

bool MysqlDao::UpdatePwd(const std::string& email, const std::string& new_pwd) {
	// 生成密码哈希future对象为了和sql事务并行执行
	auto hashFuture = _bcryptWorker.generateHashAsync(new_pwd);

	auto con = pool_->getConnection();

	Defer defer([this, &con] { pool_->returnConnection(std::move(con)); });

	try {
		if (con == nullptr) {
			return false;
		}

		// 准备查询语句
		std::unique_ptr<sql::PreparedStatement> pstmt(con->_con->prepareStatement("UPDATE user SET password_hash = ? WHERE email = ?"));

		// 哈希结果 
		auto hash_pwd = hashFuture.get();
		// 绑定参数
		pstmt->setString(1, hash_pwd);
		pstmt->setString(2, email);

		// 执行更新
		int updateCount = pstmt->executeUpdate();
		std::cout << "Updated rows: " << updateCount << std::endl;
		return true;
	}
	catch (sql::SQLException& e) {
		std::cerr << "SQLException: " << e.what();
		std::cerr << " (MySQL error code: " << e.getErrorCode();
		std::cerr << ", SQLState: " << e.getSQLState() << " )" << std::endl;
		return false;
	}
}

//检查邮箱对应的密码是否正确
bool MysqlDao::CheckPwd(const std::string& email, const std::string& pwd, UserInfo& userInfo) {
	auto con = pool_->getConnection();
	if (!con) return false;

	Defer defer([this, &con] { pool_->returnConnection(std::move(con)); });

	try {
		// STEP 1: 原子化获取用户数据 
		std::unique_ptr<sql::PreparedStatement> pstmt(
			con->_con->prepareStatement(
				"SELECT uid, email, password_hash, user_name FROM user WHERE email = ?"
			)
		);
		pstmt->setString(1, email);
		std::unique_ptr<sql::ResultSet> res(pstmt->executeQuery());

		if (!res->next()) return false; // 用户不存在 

		// STEP 2: 创建版本感知上下文 
		auto ctx = std::make_shared<ValidationContext>();
		const std::string dbHash = res->getString("password_hash");
		ctx->updateHash(dbHash); // 初始化上下文 

		// STEP 3: 异步验证（无并行任务时仍保持异步优势）
		std::future<bool> validFuture = _bcryptWorker.validatePasswordAsync(pwd, ctx);

		// STEP 4: 同步等待（优化点：可设置超时避免死锁）
		if (!validFuture.get())  return false;

		// STEP 5: 填充用户数据 
		userInfo.uid = res->getInt("uid");
		userInfo.name = res->getString("user_name");
		userInfo.email = res->getString("email");
		return true;
	}
	catch (sql::SQLException& e) {
		std::cerr << "SQLException: " << e.what();
		std::cerr << " (MySQL error code: " << e.getErrorCode();
		std::cerr << ", SQLState: " << e.getSQLState() << " )" << std::endl;
		return false;
	}
	catch (...) {
		return false; // BCrypt异常统一处理 
	}
}

//添加文件事务
int MysqlDao::AddFileTransaction(int user_id, const std::string& file_hash, const std::string& storage_path, const std::string& logical_name)
{
	auto con = pool_->getConnection();
	if (!con) return -1;
	Defer defer([this, &con] { pool_->returnConnection(std::move(con)); });

	try {
		con->_con->setAutoCommit(false);  // 开启事务 

		// 1. 校验用户存在性（避免触发外键异常）
		std::unique_ptr<sql::PreparedStatement> userCheckStmt(
			con->_con->prepareStatement("SELECT 1 FROM user WHERE uid = ?")
		);
		userCheckStmt->setInt(1, user_id);
		std::unique_ptr<sql::ResultSet> userRes(userCheckStmt->executeQuery());
		if (!userRes->next()) {
			con->_con->rollback();
			return -2;  // 用户不存在错误码（需与项目统一）
		}

		// 2. 检查文件是否已存在（利用唯一索引）
		std::unique_ptr<sql::PreparedStatement> fileCheckStmt(
			con->_con->prepareStatement("SELECT file_id FROM file_info WHERE user_id = ? AND file_hash = ?")
		);
		fileCheckStmt->setInt(1, user_id);
		fileCheckStmt->setString(2, file_hash);
		std::unique_ptr<sql::ResultSet> fileRes(fileCheckStmt->executeQuery());
		if (fileRes->next()) {
			int existing_id = fileRes->getInt("file_id");
			con->_con->rollback();
			return existing_id;  // 文件已存在，返回现有 ID 
		}

		// 3. 插入新文件记录
		std::unique_ptr<sql::PreparedStatement> insertStmt(
			con->_con->prepareStatement(
				"INSERT INTO file_info (user_id, file_hash, storage_path, logical_name) "
				"VALUES (?, ?, ?, ?)"
			)
		);
		insertStmt->setInt(1, user_id);
		insertStmt->setString(2, file_hash);
		insertStmt->setString(3, storage_path);
		insertStmt->setString(4, logical_name);
		insertStmt->executeUpdate();

		// 4. 获取自增 file_id
		std::unique_ptr<sql::Statement> lastIdStmt(con->_con->createStatement());
		std::unique_ptr<sql::ResultSet> lastIdRes(lastIdStmt->executeQuery("SELECT LAST_INSERT_ID()"));
		if (!lastIdRes->next()) {
			con->_con->rollback();
			return -1;
		}
		int new_file_id = lastIdRes->getInt(1);

		con->_con->commit();
		return new_file_id;
	}
	catch (sql::SQLException& e) {
		con->_con->rollback();
		std::cerr << "SQL Error [AddFile]: " << e.what()
			<< " (Code: " << e.getErrorCode() << ")" << std::endl;
		return -1;
	}
}

//获取文件路径
std::string MysqlDao::GetFilePath(const std::string& file_hash)
{
	auto con = pool_->getConnection();
	if (!con) return "";
	Defer defer([this, &con] { pool_->returnConnection(std::move(con)); });

	try {
		// 使用索引优化查询（idx_hash 索引前8位）
		std::unique_ptr<sql::PreparedStatement> pstmt(
			con->_con->prepareStatement("SELECT storage_path FROM file_info WHERE file_hash = ? LIMIT 1")
		);
		pstmt->setString(1, file_hash);
		std::unique_ptr<sql::ResultSet> res(pstmt->executeQuery());
		return (res->next()) ? res->getString("storage_path") : "";
	}
	catch (sql::SQLException& e) {
		std::cerr << "SQL Error [GetPath]: " << e.what() << std::endl;
		return "";
	}
}

Json::Value MysqlDao::GetFilesByUser(int user_id) {
	auto con = pool_->getConnection();
	Json::Value root;
	root["code"] = 0; // 默认成功状态码 

	if (!con) {
		root["code"] = -1; // 数据库连接失败 
		return root;
	}

	Defer defer([this, &con] { pool_->returnConnection(std::move(con)); });

	try {
		// 使用预处理语句防止SQL注入 
		std::unique_ptr<sql::PreparedStatement> pstmt(
			con->_con->prepareStatement(
				"SELECT file_hash, upload_time, logical_name "
				"FROM file_info WHERE user_id = ?"
			)
		);
		pstmt->setInt(1, user_id);

		// 执行查询并构建JSON 
		std::unique_ptr<sql::ResultSet> res(pstmt->executeQuery());
		Json::Value files(Json::arrayValue);

		while (res->next()) {
			Json::Value file;
			//file["file_id"] = res->getInt("file_id");
			file["file_hash"] = res->getString("file_hash").asStdString();
			//file["storage_path"] = res->getString("storage_path").asStdString();
			file["upload_time"] = res->getString("upload_time").asStdString();
			file["original_name"] = res->getString("logical_name").asStdString();
			files.append(file);
		}

		root["file_data"] = files;
		return root;
	}
	catch (sql::SQLException& e) {
		std::cerr << "SQL Error [GetFiles]: " << e.what()
			<< " (Code: " << e.getErrorCode()
			<< ", State: " << e.getSQLState() << ")" << std::endl;
		root["code"] = e.getErrorCode();
		return root;
	}
}
